﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using StockCommon;
using Utilities;
using System.Collections;

namespace StockPostProcessLib
{
    public class WeekIndexProcesser
    {

        private static StockDataClassesDataContext getContext()
        {
            StockDataClassesDataContext context = LinqAgent.getContext();
            return context;
        }
        public void process()
        {
            List<int> weeksToProcess = getWeeksToProcess();
            foreach (int yw in weeksToProcess)
            {
                processWeek(yw);
            }
        }
        public class DayRange
        {
            public DateTime startDay { get; set; }
            public DateTime endDay { get; set; }
        }
        protected void getRangeOfYearWeek(int yw, out DateTime startDay, out DateTime endDay)
        {
            StockDataClassesDataContext context = getContext();
            String sql = string.Format("select MIN(date) as startDay,MAX(date) as endDay from TradeCalendar where YearWeekKey= {0}", yw);
            DayRange dr = context.ExecuteQuery<DayRange>(sql).FirstOrDefault<DayRange>();
            startDay = dr.startDay;
            endDay = dr.endDay;
        }
        protected void processWeek(int yw)
        {
            System.Diagnostics.Debug.WriteLine("Process:" + yw);
            StockDataClassesDataContext context = getContext();

            DateTime startDay = DateTime.Now;
            DateTime endDay = DateTime.Now;
            getRangeOfYearWeek(yw, out startDay, out endDay);
            //get all Code
            String ss = DateUtils.toYYYYMMDD_Slash(startDay);
            String es = DateUtils.toYYYYMMDD_Slash(endDay);

            String sql = string.Format("select distinct 證券代號 from StockDaily where 日期 >='{0}' and 日期 <='{1}' and LEN(證券代號) <5 order by 證券代號", ss, es);

            List<String> codes = context.ExecuteQuery<String>(sql).ToList<String>();
            Hashtable ht = new Hashtable();
            foreach (String code in codes)
            {
                ht.Add(code, new List<StockDaily>());
            }

            WeekProcessLog wpl = (from w in context.WeekProcessLogs where w.YearWeekKey == yw select w).FirstOrDefault<WeekProcessLog>();
            if (wpl != null)
            {
                if (true == wpl.success)
                    return;
            }
            else
                wpl = new WeekProcessLog();



            String sqltmp_data = "select  *  from StockDaily where  日期 >='{0}'  and 日期 <='{1}' and  LEN(證券代號) <5  order by  日期";
            sql = String.Format(sqltmp_data, ss, es);
            List<StockDaily> datas = context.ExecuteQuery<StockDaily>(sql).ToList<StockDaily>();
            foreach (StockDaily d in datas)
            {
                String code = d.證券代號;
                if (ht.Contains(code))
                    ((List<StockDaily>)ht[code]).Add(d);
            }
            datas.Clear();
            try
            {
                foreach (String code in codes)
                {
                    if (ht.Contains(code))
                    {
                        List<StockDaily> ll = (List<StockDaily>)ht[code];
                        updateWeekIndexAndVolume(yw, code, ll);
                        ll.Clear();
                    }
                }
                ht.Clear();
                //如果都成功~~update..
                wpl.success = true;
                wpl.message = "";
            }
            catch (Exception e)
            {
                wpl.success = false;
                wpl.message = e.Message;
            }

            wpl.lastProcessDate = DateTime.Now;
            if(0==wpl.YearWeekKey)
            {
                wpl.YearWeekKey = yw;
                context.WeekProcessLogs.InsertOnSubmit(wpl);
            }
            context.SubmitChanges();

        }
        protected void updateWeekIndexAndVolume(int yw, String code, List<StockDaily> datas)
        {
            //先計算
            WeekIndexAndVolume rr = new WeekIndexAndVolume();


            rr.成交股數 = 0;
            rr.成交筆數 = 0;
            rr.成交金額 = 0;
            rr.YearWeekKey = yw;
            rr.stockCode = code;

            int sz = datas.Count;
            foreach (StockDaily sd in datas)
            {
                if (sd.開盤價 == 0)
                    continue;
                if(sd.開盤價 != null)
                {
                    rr.開盤價 = sd.開盤價; //第一筆開盤就ok
                    break;
                }
            }
            foreach (StockDaily sd in datas)
            {
                if (sd.開盤價 == 0)
                    continue;

                if (sd.收盤價 != null)
                    rr.收盤價 = sd.收盤價; //到最後一筆非空的
                
                if (sd.最高價 != null)
                    if (rr.最高價 == null)
                    {
                        rr.最高價 = sd.最高價;
                    }
                    else
                        if (sd.最高價 > rr.最高價)
                            rr.最高價 = sd.最高價;

                if (sd.最低價 != null)
                    if (rr.最低價 == null)
                    {
                        rr.最低價 = sd.最低價;
                    }
                    else
                        if (sd.最低價 < rr.最低價)
                            rr.最低價 = sd.最低價;
                if (sd.成交股數 != null)
                    rr.成交股數 += sd.成交股數;
                if (sd.成交筆數 != null)
                    rr.成交筆數 += sd.成交筆數;
                if (sd.成交金額 != null)
                    rr.成交金額 += sd.成交金額;
            }

            rr.漲跌幅度 = 0;
            if (rr.開盤價 != null)
            {
                if ((rr.最高價 != null) && (rr.最低價 != null))
                {
                    decimal dec = ((decimal)rr.最高價 - (decimal)rr.最低價);
                    if (rr.開盤價 != 0)
                    {
                        dec = dec / (decimal)rr.開盤價;
                        rr.震盪幅度 = Convert.ToDouble(dec);
                    }else
                        rr.震盪幅度 = 0;

                }
            }

            StockDataClassesDataContext context = getContext();
            WeekIndexAndVolume record = (from wi in context.WeekIndexAndVolumes where (wi.stockCode == code && wi.YearWeekKey == yw) select wi).FirstOrDefault<WeekIndexAndVolume>();
            if (record != null)
            {
                record.開盤價 = rr.開盤價;
                record.收盤價 = rr.收盤價;
                record.最高價 = rr.最高價;
                record.最低價 = rr.最低價;
                record.成交股數 = rr.成交股數;
                record.成交筆數 = rr.成交筆數;
                record.成交金額 = rr.成交金額;
                record.震盪幅度 = rr.震盪幅度;
                context.SubmitChanges();
                return;
            }
            rr.id = NewGUID.create("week");
            context.WeekIndexAndVolumes.InsertOnSubmit(rr);
            context.SubmitChanges();
        }

        protected List<int> getWeeksToProcess()
        {
            int sw = getLastProcessedYearWeek();
            int ew = getCurrentYearWeek();

            StockDataClassesDataContext context = getContext();
            String sql = "select distinct YearWeekKey from TradeCalendar where YearWeekKey >={0} and YearWeekKey <= {1} order by YearWeekKey";
            sql = string.Format(sql, sw, ew);
            List<int> result = context.ExecuteQuery<int>(sql).ToList<int>();
            return result;
        }
        protected int getCurrentYearWeek()
        {
            StockDataClassesDataContext context = getContext();
            DateTime d = DateUtils.getDateOnly(DateTime.Now);

            TradeCalendar tc = (from th in context.TradeCalendars where th.date.Equals(d) select th).FirstOrDefault<TradeCalendar>();
            int result = 0;
            if (tc != null)
                result = (int)tc.YearWeekKey;
            else
            {
                throw new Exception("TradeCalender is not enough!");
            }
            return result;
        }
        protected int getLastProcessedYearWeek()
        {
            StockDataClassesDataContext context = getContext();
            int? maxk = context.ExecuteQuery<int?>("select min(YearWeekKey) from WeekProcessLogs where WeekProcessLogs.success <> 1").FirstOrDefault();
            int result = 200407;

            if (maxk == null)
            {
                maxk = context.ExecuteQuery<int?>("select max (YearWeekKey)  from WeekProcessLogs").FirstOrDefault();
            }
    
            if (maxk != null)
            {
                result = (int)maxk;    
            }
            return result;
        }


    }
}
